
package assdraw2.canvas.abstraction;


import java.util.Vector;

import assdraw2.canvas.abstraction.event.DrawingEvent;
import assdraw2.canvas.abstraction.event.DrawingListener;


public class CanvasShapeModel
{
    private ZOrderShapeList shapes;
    private Vector<DrawingListener> listeners;
    private int width;
    private int height;
    
    /**
     * Creates a drawing of default size. 
     */
    public CanvasShapeModel()
    {
        shapes = new ZOrderShapeList();
        listeners = new Vector<DrawingListener>();
        
        width = 200;
        height = 200;
    }
    
    /**
     * Create a drawing with a specified size
     * @param width is the width, in pixels, of the drawing
     * @param height is the height, in pixels, of the drawing
     */
    public CanvasShapeModel(int width, int height)
    {
        this();
        
        this.width = width;
        this.height = height;
    }
    
    /**
     * Add a given rectangle to the drawing
     * @param r is the rectangle to add
     */
    public void addShape(Shape s)
    {
    	shapes.addShape(s);
        updateListeners(s, DrawingEvent.SHAPE_ADDED);
    }
    
    public Vector<Shape> getShapes()
    {
        return shapes.getShapes();
    }
    
    public void setShapes(Vector<Shape> v){
    	shapes.setShapes(v);
    }
    
    public void addDrawingListener(DrawingListener l)
    {
        if (!listeners.contains(l)) {
            listeners.add(l);
        }
    }
    
    public void removeDrawingListener(DrawingListener l)
    {
        listeners.remove(l);
    }
    
    private void updateListeners(Shape s, int kind)
    {
    	for(DrawingListener listener: listeners) {
            listener.update(new DrawingEvent(this, kind, s));
        }
    }
    
	/**
	 * Brings the rectangle to the front
	 * @param r Rectangle
	 */
	public void bringToFront(Shape s) {		
		shapes.bringToFront(s);
		updateListeners(s, DrawingEvent.SHAPE_MOVED);		
	}

	/**
	 * Sends rectangle to the back. It will be the last one.
	 * @param r Rectangle
	 */
	public void sendToBack(Shape s){ 		
		shapes.sendToBack(s);
		updateListeners(s, DrawingEvent.SHAPE_MOVED);		
	}

	/**
	 * Getter for width
	 * @return width
	 */
	public double getWidth() {
		return width;
	}

	/**
	 * Getter for height
	 * @return height
	 */
	public double getHeight() {
		return height;
	}

	/**
	 * Removes rectangle
	 */
	public void removeShape(Shape s) {
		shapes.removeShape(s);
		updateListeners(s, DrawingEvent.SHAPE_DELETED);
	}

	/**
	 * Ungroups the shape and inserts its components in its place
	 * 
	 * @param s shape to be ungrouped
	 */
	public void ungroup(Shape s) {
		Vector<Shape> v = shapes.getShapes();
		
		Vector<Shape> components = s.ungroup();
		if(components != null){
			int index = v.indexOf(s);
			shapes.removeShape(s);
			v.addAll(index, components);
		}
		
		updateListeners(null, DrawingEvent.SHAPE_UNGROUP);
	}	

	/**
	 * Groups shapes into a new ShapesGroup
	 * 
	 * @param list shapes to be grouped
	 */
	
	public void group(Vector<Shape> list) {
		Vector<Shape> zOrder = shapes.getShapes();
		Vector<Shape> groupList = new Vector<Shape>();
		for(int i=0; i<zOrder.size(); i++){
			if(list.contains(zOrder.get(i))){
				groupList.add(zOrder.get(i));				
			}
		}
				
		for(Shape s : list){
			shapes.removeShape(s);
		}
		Shape newShape = new ShapeGroup(groupList);
		shapes.addShape(newShape);
		updateListeners(newShape, DrawingEvent.SHAPE_GROUP);
	}
	
	public void sizeUp(Vector<Shape> list) {
		for(Shape s:list)
			s.scale(1.1, 1.1);
		
		updateListeners(new ShapeGroup(list), DrawingEvent.RESIZE);
	}
	
	public void sizeDown(Vector<Shape> list) {
		for(Shape s:list)
			s.scale(0.9, 0.9);
	
		updateListeners(new ShapeGroup(list), DrawingEvent.RESIZE);
	}
	
}
